/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package immt.ui;

import ij.ImagePlus;
import immt.util.ConfigurationManager;
import immt.util.Functions;
import java.awt.Point;
import java.util.ArrayList;

/**
 *
 * @author Gaston
 */
public class SnakesResult extends javax.swing.JFrame {

    private double[] topSnakeValues; 
    
    private double[] botSnakeValues; 
    
    /**
     * Creates new form SnakesResult
     */
    public SnakesResult() {
        initComponents();
    }
    
    public SnakesResult(ImagePlus img, double[] topSnake, double[] botSnake)
    {
        initComponents();
        topSnakeValues = topSnake;
        botSnakeValues = botSnake;
        imagePanel1.setImage(img);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        imagePanel1 = new immt.ui.ImagePanel();
        jLabel1 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTextArea1 = new javax.swing.JTextArea();
        jButton1 = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();
        jButton3 = new javax.swing.JButton();
        jLabel2 = new javax.swing.JLabel();
        promedio = new javax.swing.JLabel();
        jButton4 = new javax.swing.JButton();
        jLabel3 = new javax.swing.JLabel();
        maximo = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        minimo = new javax.swing.JLabel();
        jLabel5 = new javax.swing.JLabel();
        desviacion = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        imagePanel1.setPreferredSize(new java.awt.Dimension(800, 652));

        javax.swing.GroupLayout imagePanel1Layout = new javax.swing.GroupLayout(imagePanel1);
        imagePanel1.setLayout(imagePanel1Layout);
        imagePanel1Layout.setHorizontalGroup(
            imagePanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 800, Short.MAX_VALUE)
        );
        imagePanel1Layout.setVerticalGroup(
            imagePanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 652, Short.MAX_VALUE)
        );

        jLabel1.setText("Set de Puntos");

        jTextArea1.setColumns(20);
        jTextArea1.setRows(5);
        jScrollPane1.setViewportView(jTextArea1);

        jButton1.setText("Agregar Otro");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jButton2.setText("Mapear puntos al snake");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        jButton3.setText("Metodo Simple");
        jButton3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton3ActionPerformed(evt);
            }
        });

        jLabel2.setText("Promedio:");

        promedio.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);

        jButton4.setText("Metodo Rectas");
        jButton4.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton4ActionPerformed(evt);
            }
        });

        jLabel3.setText("Maximo:");

        maximo.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);

        jLabel4.setText("Minimo:");

        minimo.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);

        jLabel5.setText("Desviacion:");

        desviacion.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap(22, Short.MAX_VALUE)
                .addComponent(imagePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel1)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 159, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                        .addComponent(jButton4, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(jButton3, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 159, Short.MAX_VALUE))
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                        .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                            .addComponent(jLabel5)
                            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(desviacion, javax.swing.GroupLayout.PREFERRED_SIZE, 64, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                            .addComponent(jLabel4)
                            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(minimo, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 159, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGroup(layout.createSequentialGroup()
                            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addComponent(jLabel3)
                                .addComponent(jLabel2))
                            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addComponent(promedio, javax.swing.GroupLayout.DEFAULT_SIZE, 71, Short.MAX_VALUE)
                                .addComponent(maximo, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(22, 22, 22)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(52, 52, 52)
                        .addComponent(jButton1)
                        .addGap(18, 18, 18)
                        .addComponent(jButton2)
                        .addGap(41, 41, 41)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel2)
                            .addComponent(promedio, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel3)
                            .addComponent(maximo, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel4)
                            .addComponent(minimo, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel5)
                            .addComponent(desviacion, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addGap(15, 15, 15)
                        .addComponent(jButton3)
                        .addGap(18, 18, 18)
                        .addComponent(jButton4))
                    .addComponent(imagePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        Point point1 = imagePanel1.GetPoint1();
        
        Point point2 = imagePanel1.GetPoint2();
        
        if(point1 != null && point2 != null)
            jTextArea1.append(point1.getX() +","+point1.getY() + "   " + point2.getX() +","+point2.getY() + "\n");
        
        imagePanel1.ClearPoints();
    }//GEN-LAST:event_jButton1ActionPerformed

    ArrayList<immt.util.Point> mappedPoints;
    
    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
        ArrayList<Point> points = imagePanel1.GetPoints();
        mappedPoints = new ArrayList<>();
        double[] toUse = topSnakeValues;
        for(Point p: points)
        {          
            immt.util.Point pointMappedToSnake = MapPointToSnake(p, toUse);
            mappedPoints.add(pointMappedToSnake);
            if(toUse == topSnakeValues)
                toUse = botSnakeValues;
            else
                toUse = topSnakeValues;
        }
        imagePanel1.paintPoints(mappedPoints);
    }//GEN-LAST:event_jButton2ActionPerformed

    private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton3ActionPerformed
        if(mappedPoints != null)
        {
            CalculateStatistics(mappedPoints);
        }        
    }//GEN-LAST:event_jButton3ActionPerformed

    private void CalculateStatistics(ArrayList<immt.util.Point> points)
    {
        double ppm = Double.parseDouble(ConfigurationManager.getAppSetting("ppm"));
        immt.util.Point firstPoint = null;
        double sumOfDistances = 0;
        
        // Need points??
        immt.util.Point maxPoint = new immt.util.Point(0,0);
        immt.util.Point minPoint = new immt.util.Point(9999,9999);
        
        double minDistance = Double.MAX_VALUE;
        double maxDistance = Double.MIN_VALUE;
        
        for(immt.util.Point p : points)
        {
            if(p.getyCoord() < minPoint.getyCoord())
                minPoint = p;
            if(p.getyCoord() > maxPoint.getyCoord())
                maxPoint = p;
            
            if (firstPoint == null)
                firstPoint = p;
            else
            {              
                double distance = EuclidianDistance(firstPoint, p.getxCoord(), p.getyCoord()) * ppm;
                if(distance > maxDistance )
                    maxDistance = distance;
                if(distance < minDistance)
                    minDistance = distance;
                sumOfDistances += distance;
                firstPoint = null;
            }
        }
        double mean = sumOfDistances / (points.size()/2);
        promedio.setText(String.valueOf(mean).substring(0, 5)); 
        minimo.setText(String.valueOf(minDistance).substring(0,5));
        maximo.setText(String.valueOf(maxDistance).substring(0, 5));
        desviacion.setText(String.valueOf(GetStandarDeviation(mean, points)));    
    }

    private double GetStandarDeviation(double mean, ArrayList<immt.util.Point> points)
    {     
        double ppm = Double.parseDouble(ConfigurationManager.getAppSetting("ppm"));
        double result = 0;
        immt.util.Point firstPoint = null;
    
        for(immt.util.Point p : points)
        {
            if (firstPoint == null)
                firstPoint = p;
            else
            {              
                double distance = EuclidianDistance(firstPoint, p.getxCoord(), p.getyCoord()) * ppm;
                System.out.println("DISTANCE:" + distance);
                System.out.println("MEAN:" + mean);
                result += Math.pow((distance - mean), 2);
                firstPoint = null;
            }
        }
        return Math.sqrt(result / (points.size() / 2));
    }
    
    int offset = 5;
    
    private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton4ActionPerformed
        if(mappedPoints != null)
        {
            ArrayList<immt.util.Point> newPoints =  new ArrayList<immt.util.Point>();
            
            immt.util.Point firstPoint = null;
            for(immt.util.Point p : mappedPoints)
            {
                if (firstPoint == null)
                {
                    firstPoint = p;
                    
                    double left = topSnakeValues[(int)firstPoint.getxCoord() - offset];                    
                    
                    double right = topSnakeValues[(int)firstPoint.getxCoord() + offset];
                                      
                    // y = ax + b
                    
                    // a = (y2 - y1) / (x2 - x1)
                    double a =  (left - right) / (((int)firstPoint.getxCoord() - offset) - ((int)firstPoint.getxCoord() + offset));
                    
                    // b = y - (a * x)
                    double b = topSnakeValues[(int)firstPoint.getxCoord() - offset] - (a * ((int)firstPoint.getxCoord() - offset));

                    // Perpedincular line is with 1/ -a
                    double aPerp = (1/a) * -1;                    
                    
                    double newB = topSnakeValues[(int)firstPoint.getxCoord()] - (aPerp * ((int)firstPoint.getxCoord()));
                    
                    /*
                    for(int i = 0; i < 600; i++)
                    {
                        double yy = a * i + b;
                        imagePanel1.PaintPoint(i, yy);
                    }
                    
                     for(int i = 0; i < 1000; i++)
                    {
                        double yy = aPerp * i + newB;
                        imagePanel1.PaintPoint(i, yy);
                    }
                    */
                    double lowest = 999999;
                    int lowestX = -1;
                    
                    int it = 0;
                    for(double d : botSnakeValues)
                    {
                        // y = a x + b                        
                        double y = (aPerp * it) + newB;
                        
                        double diff = d - y;
                        diff = Math.abs(diff);
                        
                        if (diff < lowest)
                        {
                            lowest = diff;
                            lowestX = it;
                        }
                        it++;                        
                    }
                    //System.out.println("LOWEST =" + lowestX);
                    
                    newPoints.add(firstPoint);
                    newPoints.add(new immt.util.Point(lowestX, botSnakeValues[lowestX]));
                }
                else
                {                    
                    firstPoint = null;
                }
            }
            
            CalculateStatistics(newPoints);
        }
    }//GEN-LAST:event_jButton4ActionPerformed

    immt.util.Point MapPointToSnake(Point p, double[] points)
    {       
       double closestDistance = 99999;
       immt.util.Point closestPoint = new immt.util.Point();
               
       double currentDistance;
       for(int i = 0; i < points.length; i++)
       {           
           currentDistance = EuclidianDistance(p, i, points[i]);
           if(currentDistance < closestDistance)
           {
               closestDistance = currentDistance;
               closestPoint.setxCoord(i);
               closestPoint.setyCoord(points[i]);
           }
       } 
       return closestPoint;
    }
    
    double EuclidianDistance(Point originalPoint, double x, double y)
    {
      return Math.sqrt(Math.pow(originalPoint.x - x,2) + Math.pow(originalPoint.y - y, 2));    
    }
    
    double EuclidianDistance(immt.util.Point originalPoint, double x, double y)
    {
      return Math.sqrt(Math.pow(originalPoint.getxCoord() - x,2) + Math.pow(originalPoint.getyCoord()- y, 2));    
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(SnakesResult.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(SnakesResult.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(SnakesResult.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(SnakesResult.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new SnakesResult().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel desviacion;
    private immt.ui.ImagePanel imagePanel1;
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JButton jButton3;
    private javax.swing.JButton jButton4;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextArea jTextArea1;
    private javax.swing.JLabel maximo;
    private javax.swing.JLabel minimo;
    private javax.swing.JLabel promedio;
    // End of variables declaration//GEN-END:variables
}
